#include <stdio.h>
#include <glib.h>

// ref: https://www.cnblogs.com/tears-of-ramos/p/3929175.html
// tip: glib简单记录包括字符串，主循环，回调函数和xml解析 

gchar* demo(char* format, ...)
{
    va_list argp;
	// 参数右到左入栈的，所以左到右的参数分别在栈顶到栈底
    va_start(argp, format);
	
	gchar* ret = g_strdup_vprintf("%s %s %s %d",argp);
	
	va_end(argp);
	
	return ret;
}

int main()
{	
    // 复制str并返回它的一个拷贝。并非返回原来字符串的指针而是重新申请一块内存将其指针返回。
	g_print("\n1. gchar* g_strdup(const gchar* str)\n");
	
	gchar* 	name 	= "kehuadong";
	gchar* 	hj 			= g_strdup(name);
    gchar* 	test_str 	= g_strdup(hj);
	
    g_free(hj);
    hj = NULL;
	
    g_print("%s\n", test_str);
	g_free(test_str);
	test_str = NULL;
	
	
	// -----------------------------------------------------------------------
	// 创建一个长度为length并被fill_char填充的字符串。如果fill_char为0则创建一个空字符串
	g_print("\n2. gchar* strnfill(gsize length, gchar* fill_char)\n");
	
	test_str = g_strnfill(10, 'a');
    g_print("%s\n", test_str);
    g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
	// 像sprintf()一样格式化字符串和参数。但是，你没必要像sprintf()一样创建
	// 和指定一个缓冲区，GLib将这些自动做了。适合用于字符串拼
	g_print("\n3. gchar* g_strdup_printf(const gchar* format, ...)\n");
	
	
	test_str = g_strdup_printf("%s_%u", name, 1);
    g_print("%s\n", test_str);
	g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
	// 测试g_strdup_vprintf的拼接功能 类似上面g_strdup_printf函数的功能
	g_print("\n4. gchar* g_strdup_printf(const gchar* format, ...)\n");
	
	test_str = demo("", "hj", "is", "number", 1);
    g_print("%s\n", test_str);
    g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
	// 它接受任意数量的string作为参数，并返回它们的连接后的字符串。必须将NULL作为这个函数的最后一个参数
	g_print("\n5 gchar* g_strconcat(const gchar* string1, ..., NULL)\n");
	
	hj = g_strdup(name);
    test_str = g_strconcat("   ", hj, ":", "good person", NULL);
	
	// 这里不释放hj,下面会继续使用
	
    g_print("%s\n", test_str);
    g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
	// 拷贝src到dest，包括最后的NULL字符。如果它执行成功，会返回dest中结束符拷贝的指针。
	g_print("\n6 gchar* g_stpcpy(gchar* dest, const gchar* src)\n");
	
	test_str = (gchar*)g_malloc0(strlen(hj));
    g_stpcpy(test_str, hj);
	
    g_print("%s\n", test_str);
	
    g_slice_free1(strlen(hj), test_str);
    test_str = NULL;
	
	// 这里不释放hj,下面会继续使用
	
	
	// -----------------------------------------------------------------------
	// 你必须确保string有足够大的空间。而且你必须要用n来指定这个缓冲区的大小。
	// 返回值是输出字符串的长度，也有可能这个输出字符串为了适应缓冲区的大小而被截断 
	g_print("\n7 gint g_snprintf(gchar* string, gulong n, const gchar* format, ...)\n");
	
#define MAX_LEN 100
	gchar 	buff_str[MAX_LEN+1] = {0};
	guint64 imsi 		= 123456789;
	gint 	len 		= 0;
	
	len += g_snprintf(buff_str+len, MAX_LEN-len,
				"%d, %d, %d, %"G_GINT64_FORMAT,
				1, 2, 3, imsi);				
    g_print("%s\n",buff_str);
	
	
	// -----------------------------------------------------------------------
	// 测试g_strchug删除字符串开始的空格
	g_print("\n8 gchar* g_strchug(gchar* string)\n");
	
	test_str = g_strconcat("   ", hj, ":", "good person     ", NULL);
    gchar* test_str2 = g_strchug(test_str);
	
	g_print("%s\n", test_str);
    g_print("%s\n", test_str2);
	g_print("%d\n", test_str == test_str2); // 表面只是内部移动了内容
	
	// 这里不释放test_str,下面会继续使用
	
	
	// -----------------------------------------------------------------------
	// 将string结尾的空格都删掉，返回string
	g_print("\n9 gchar* g_strchomp(gchar* string)\n");
	
	test_str = g_strchomp(test_str);
    g_print("%s\n", test_str);
    g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
    // 将string开头和结尾的空白字符都删掉，返回string。
	g_print("\n10 gchar* g_strstrip(gchar* string)\n");
	
	test_str = g_strconcat("   ", hj, ":", "good person     ", NULL);
    test_str = g_strstrip(test_str);
    g_print("%s\n", test_str);
	
	// 这里不释放test_str,下面会继续使用
	// 这里不释放hj,下面会继续使用
	
	
	// -----------------------------------------------------------------------
    // 将string中的delimiters各个字符都替换为new_delimiter这一个字符
	g_print("\n11 gchar* g_strdelimit(gchar* string, const gchar* delimiters, gchar* new_delimiter)\n");
	
	test_str = g_strdelimit(test_str, "good", 'a');
    g_print("%s\n", test_str);
    g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
    // 在haystack中遍历haystack_len长度，如果找到了needle字串，则返回这个位置的指针，如果没有找到则返回NULL
    g_print("\n12 gchar* g_strstr_len(const gchar* haystack, gssize haystack_len, const gchar* needle)\n");
	
    test_str = g_strstr_len(name, strlen(name), "hua");
    g_print("%s, isShared: %d\n", test_str, test_str == g_strstr_len(name, strlen(name), "hua"));
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------	  
    // 类似于g_strstr_len，这个函数将会从后面开始查找，但是它并没有haystack_len参数。
    g_print("\n13 gchar* g_strrstr(const gchar* haystack, const gchar* needle)\n");
	
    test_str = g_strrstr(name, "hua");
    g_print("%s, isShared: %d\n",test_str, test_str == g_strrstr(name, "hua"));	
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------	  
    // 与g_strrstr()相同，但是它只在前haystack_len个字符中查找,第二个参数是-1表示在整个字符串中找
    g_print("\n14 gchar* g_strrstr_len(gchar* haystack, gssize haystack_len, gchar* needle)\n");
	
    test_str = g_strrstr_len(name, -1, "hua");
    g_print("%s, isShared: %d\n",test_str, test_str == g_strrstr_len(name, -1, "hua"));
	test_str = NULL;
	
    test_str = g_strrstr_len(name, 5, "hua");
    g_print("%s, isShared: %d\n",test_str, test_str == g_strrstr_len(name, 5, "hua"));
	test_str = NULL;
	
	// -----------------------------------------------------------------------	 
    // 将string转为双字长度的浮点数。如果你提供了一个有效的endptr指针地址，
	// 这个函数会将指针设置到string中被转换的最后一个字符的位置
    g_print("\n15 gdouble g_ascii_strtod(const gchar* nptr, gchar** endptr)\n");
	
	gchar* 	strdouble 	= "11.11";
    gdouble test_duble = g_ascii_strtod(strdouble, NULL);
    g_print("%.2f\n",test_duble);
	
	
	// -----------------------------------------------------------------------	
    // 使用delimiter来将string切割成至多max_tokens个部分。返回值是新申请的一个字符串数组，用来保存被切割的这些部分。
    // 这个字符串数组必须由你自己释放。 如果输入字符串是空的，这个返回值也是一个空的数组。 该法不改变原string	
    g_print("\n16 gchar** g_strsplit(const gchar* string, const gchar* delimiter, gint max_tokens)\n");
	
	gchar* 	strint 		= "123456;8910";
    gchar** str_array 	= g_strsplit(strint, ";" , 3);
    g_print("%s, %s, isShared %d\n",str_array[0], str_array[1], strint == str_array[0]);
	
	// 这里不释放str_array,下面会继续使用
	
	
	// -----------------------------------------------------------------------	
    // 将字符串数组组合成单个字符串，并将这个新申请的字符串返回。
	// 如果separator不空，g_str_joinv()会在每个字符串之间添加上一个separator分隔符
    g_print("\n17 gchar *g_str_joinv(const gchar *separator, gchar **str_array)\n");
	
    test_str = g_strjoinv(",", str_array);
    g_print("%s\n", test_str);
	
    g_strfreev(str_array);	
    str_array = NULL;
	
    g_free(test_str);
    test_str = NULL;
	
	
	// -----------------------------------------------------------------------
	// 测试g_ascii_strtoll将字符串转成对应整形的功能第三个参数是指的几进制
	g_print("\n18 g_ascii_strtoll\n");
	
	g_print("%s\n", strint);
	
    test_str = strchr(strint, ';');
	g_print("%s, shared=%d\n", test_str, test_str == &strint[6]);
	
    len = (gint)g_ascii_strtoll(strint, NULL, 10);
    g_print("%d\n", len);
	
    strint = test_str + 1;
    len = (gint)g_ascii_strtoll(strint, NULL, 10);
    g_print("%d\n", len);
    
    test_str = NULL;
	
}

/*
Makefile内容可以是这样

CC = gcc
CFLAGS = -g -Wall `pkg-config --libs --cflags glib-2.0`

run: 2021_07_26_test_string
	@./2021_07_26_test_string

2021_07_26_test_string: 2021_07_26_test_string.c
	@$(CC) -o $@ $^ $(CFLAGS) 
	
clean:
	rm 2021_07_26_test_string
*/
